package com.zhu.tool_test.starke.framework.redis.event;


import com.zhu.tool_test.starke.framework.redis.EventProcesser;
import com.zhu.tool_test.starke.util.lang.Strings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.dao.QueryTimeoutException;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author  4everlynn
 * @version V1.0
 * @description
 * @date 2019-04-16
 */
@Slf4j
public abstract class AbstractEventListener implements ApplicationRunner, EventResponseResolver {
    @Autowired
    private EventProcesser processer;

    @Autowired
    @Qualifier("starke-string-redis-tmpl")
    private RedisTemplate<String, Object> redisTemplate;

    private ExecutorService service;

    /**
     * 监听事件的名称数组,由于队列使用BrPop实现,有多少个需要监听的队列就会启用多少个线程
     *
     * @return 队列名称数组
     */
    public abstract String[] eventName();

    private void startPopThread() {
        if (null == service) {
            service = Executors.newFixedThreadPool(this.eventName().length);
        }
        for (String event : this.eventName()) {
            service.submit(() -> {
                while (true) {
                    try {
                        String htvEvent
                                = (String) redisTemplate.opsForList().rightPop(event, 0, TimeUnit.SECONDS);
                        // 消息获取时间
                        Date responseTime = new Date();
                        if (Strings.isNullOrEmpty(htvEvent)) {
                            continue;
                        }
                        EventResponse response = this.handleMessage(htvEvent);
                        if (null == response) {
                            continue;
                        }
                        if (null == response.getResponseTime()) {
                            response.setResponseTime(responseTime);
                        }
                        processer.dispatch(response.getModuleName(), response);
                    } catch (RedisConnectionFailureException exception) {
                        break;
                    } catch (QueryTimeoutException ignored) {

                    } catch (Exception e) {
                        log.error("", e);
                    }
                }
            });
        }
    }


    @Override
    public void run(ApplicationArguments args) {
        try {
            startPopThread();
        } catch (Exception e) {
            log.error("", e);
        }
    }
}
